#pragma once

#include <iostream>
#include <string>

using namespace std;

template<class T>
class MyArray {
public:
    // 构造函数
    MyArray(int capacity) {
        this->m_Capacity = capacity;
        this->m_Size = 0;
        this->pAddress = new T[this->m_Capacity];
        cout << "MyArray 构造函数" << endl;
    }

    // 拷贝构造函数
    MyArray(const MyArray &arr) {
        this->m_Capacity = arr.m_Capacity;
        this->m_Size = arr.m_Size;
        // 浅拷贝，编译器默认的就是这样，但是这样会引起重复释放内容的错误
        // this->pAddress = arr.pAddress;

        // 自己实现深拷贝
        this->pAddress = new T[arr.m_Capacity];
        // 将 arr 中的数据全部拷贝
        for (int i = 0; i < this->m_Size; ++i) {
            this->pAddress[i] = arr.pAddress[i];
        }

        cout << "MyArray 拷贝构造函数" << endl;
    }

    // 重载 operator= 运算符，防止浅拷贝的问题
    MyArray &operator=(const MyArray &arr) {
        // 先判断原来堆区是否又数据，如果有，先释放
        if (this->pAddress != nullptr) {
            cout << "MyArray operator= 调用" << endl;
            delete[]this->pAddress;
            this->pAddress = nullptr;
            this->m_Size = 0;
            this->m_Capacity = 0;
        }

        this->m_Capacity = arr.m_Capacity;
        this->m_Size = arr.m_Size;
        this->pAddress = new T[arr.m_Capacity];
        for (int i = 0; i < this->m_Size; ++i) {
            this->pAddress[i] = arr.pAddress[i];
        }
        return *this;
    }

    // 析构函数
    ~MyArray() {
        if (this->pAddress != nullptr) {
            cout << "MyArray 析构函数" << endl;
            delete[]this->pAddress;
            this->pAddress = nullptr;
        }
    }

    // 尾插法
    void pushBack(const T &value) {
        // 判断容量是否等于大小
        if (this->m_Capacity == this->m_Size) {
            return;
        }

        // 尾部插入数据
        this->pAddress[this->m_Size] = value;
        // 数组长度加一
        this->m_Size++;
    }

    // 尾删法
    void popBack() {
        // 让用户访问不到最后一个元素即可，实际上是逻辑删除，并非物理删除
        if (this->m_Size == 0) {
            return;
        }
        this->m_Size--;
    }

    // 通过下标获取元素，重载 [] 运算符
    T &operator[](int index) {
        return this->pAddress[index];
    }

    // 返回数组容量
    int getCapacity() {
        return this->m_Capacity;
    }

    // 返回数组大小
    int getSize() {
        return this->m_Size;
    }

private:
    // 指针指向堆区真实开辟的数组
    T *pAddress;

    // 数组容量
    int m_Capacity;

    // 数组的大小
    int m_Size;

};


